package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	bolt "go.etcd.io/bbolt"
	"log"
	"os"
	"time"
)

func main() {
	// Open the my.db data file in your current directory.
	// It will be created if it doesn't exist.
	db, err := bolt.Open("my.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	go func() {
		// Grab the initial stats.
		prev := db.Stats()
		for {
			// Wait for 10s.
			time.Sleep(1 * time.Second)
			// Grab the current stats and diff them.
			stats := db.Stats()
			diff := stats.Sub(&prev)
			// Encode stats to JSON and print to STDERR.
			json.NewEncoder(os.Stderr).Encode(diff)
			// Save stats for the next loop.
			prev = stats
		}
	}()

	db.Update(func(tx *bolt.Tx) error {
		_, err = tx.CreateBucket([]byte("MyBucket"))
		if err != nil {
			return fmt.Errorf("create bucket: %s", err)
		}
		return nil
	})

	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("MyBucket"))
		err := b.Put([]byte("answer"), []byte("32"))
		err = b.Put([]byte("andy"), []byte("42"))
		err = b.Put([]byte("anger"), []byte("52"))
		return err
	})

	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("MyBucket"))
		v := b.Get([]byte("answer"))
		fmt.Printf("The answer is: %s\n", v)
		return nil
	})

	db.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		b := tx.Bucket([]byte("MyBucket"))
		c := b.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			fmt.Printf("key=%s, value=%s\n", k, v)
		}
		return nil
	})

	db.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		c := tx.Bucket([]byte("MyBucket")).Cursor()
		prefix := []byte("an")
		for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() {
			fmt.Printf("prefix %s key=%s, value=%s\n", prefix, k, v)
		}
		return nil
	})

	db.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		b := tx.Bucket([]byte("MyBucket"))
		b.ForEach(func(k, v []byte) error {
			fmt.Printf("foreach key=%s, value=%s\n", k, v)
			return nil
		})
		return nil
	})

	time.Sleep(2 * time.Second)
}